///\todo upgrade

//////////////////////////////////////////////////////////////////////////////////
//                                                                              //
//  This file is part of the buola project (https://code.google.com/p/buola/).  //
//                                                                              //
//  Copyright(c) 2007-2012 Xavi Gratal                                          //
//  gratal AT gmail DOT com                                                     //
//                                                                              //
//  Buola is free software: you can redistribute it and/or modify               //
//  it under the terms of the GNU General Public License as published by        //
//  the Free Software Foundation, either version 3 of the License, or           //
//  (at your option) any later version.                                         //
//                                                                              //
//  Buola is distributed in the hope that it will be useful,                    //
//  but WITHOUT ANY WARRANTY; without even the implied warranty of              //
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the               //
//  GNU General Public License for more details.                                //
//                                                                              //
//  You should have received a copy of the GNU General Public License           //
//  along with buola.  If not, see <http://www.gnu.org/licenses/>.              //
//                                                                              //
//////////////////////////////////////////////////////////////////////////////////

#ifndef _BUOLA_IMAGE_VIEWS_CMASKEDVIEW_H_
#define _BUOLA_IMAGE_VIEWS_CMASKEDVIEW_H_

#include <buola/image/format.h>

namespace buola { namespace img {

template<typename tBase,typename tMask>
class CMaskedAccessor
{
    typedef typename tBase::TAccessor TBaseAccessor;
    typedef typename tMask::TAccessor TMaskAccessor;
    typedef typename TBaseAccessor::TPixel TPixel;
public:
    CMaskedAccessor(const TBaseAccessor &pBase,const TMaskAccessor &pMask)
        :   mBase(pBase)
        ,   mMask(pMask)
    {}

    CMaskedAccessor(const CMaskedAccessor&)=default;

    const CMaskedAccessor &operator=(const TBaseAccessor &pRH) const
    {
        mBase.Blend(pRH,mMask);
        return *this;
    }

    const CMaskedAccessor &operator=(const TPixel &pRH) const
    {
        mBase.Blend(pRH,mMask);
        return *this;
    }

private:
    TBaseAccessor mBase;
    TMaskAccessor mMask;
};

template<typename tBaseIt,typename tMaskIt,typename tAccessor>
class CMaskedIterator
{
public:
    CMaskedIterator()=default;
    CMaskedIterator(const CMaskedIterator&)=default;
    
    CMaskedIterator(const tBaseIt &pBaseIt,const tMaskIt &pMaskIt)
        :   mBaseIt(pBaseIt)
        ,   mMaskIt(pMaskIt)
    {}

    ~CMaskedIterator()=default;
    CMaskedIterator &operator=(const CMaskedIterator&)=default;

    CMaskedIterator &operator++()
    {
        ++mBaseIt;
        ++mMaskIt;
        return *this;
    }

    CMaskedIterator operator++(int)
    {
        CMaskedIterator lI(*this);
        ++*this;
        return lI;
    }

    CMaskedIterator &operator--()
    {
        --mBaseIt;
        --mMaskIt;
        return *this;
    }

    CMaskedIterator operator--(int)
    {
        CMaskedIterator lI(*this);
        --*this;
        return lI;
    }

    CMaskedIterator operator+(ptrdiff_t pInc)
    {
        return {mBaseIt+pInc,mMaskIt+pInc};
    }

    tAccessor operator*() const
    {
        return tAccessor(*mBaseIt,*mMaskIt);
    }

    bool operator==(const CMaskedIterator &pRH) const
    {
        return (mBaseIt==pRH.mBaseIt);
    }

    bool operator!=(const CMaskedIterator &pRH) const
    {
        return (mBaseIt!=pRH.mBaseIt);
    }

private:
    tBaseIt mBaseIt;
    tMaskIt mMaskIt;
};
    
template<typename tBase,typename tMask>
class CMaskedView
{
public:
    typedef CMaskedView<tBase,tMask> TView;
    typedef typename tBase::TPixel TPixel;

    typedef typename tBase::TValue TValue;
    typedef CMaskedAccessor<tBase,tMask> TAccessor;
    typedef CMaskedIterator<typename tBase::TXIterator,typename tMask::TXIterator,TAccessor> TXIterator;
    typedef CMaskedIterator<typename tBase::TYIterator,typename tMask::TYIterator,TAccessor> TYIterator;
    typedef CViewRow<TView> TRow;
    typedef CViewCol<TView> TCol;

    CMaskedView()=default;
    
    CMaskedView(const tBase &pBase,const tMask &pMask)
        :   mBase(pBase)
        ,   mMask(pMask)
    {}

    CMaskedView(const CMaskedView&)=default;
    CMaskedView &operator=(const CMaskedView&)=default;

public:
    bool IsNull() const                         {   return mBase.IsNull();  }
    bool empty() const                          {   return mBase.empty();    }

    const CSize_i &Size() const                 {   return mBase.Size();   }
    int Width() const                           {   return mBase.Width(); }
    int Height() const                          {   return mBase.Height(); }

    TAccessor operator()(const CPoint_i &pP) const     {   return {mBase(pP),mMask(pP)};     }
    TAccessor operator()(int x,int y) const            {   return {mBase(x,y),mMask(x,y)};   }

    TXIterator XIterator(int x,int y) const {   return {mBase.XIterator(x,y),mMask.XIterator(x,y)}; }
    TYIterator YIterator(int x,int y) const {   return {mBase.YIterator(x,y),mMask.YIterator(x,y)}; }

    TRow Row(int y) {   return {*this,y};   }
    TCol Col(int x) {   return {*this,x};   }
    
private:
    typename tBase::template MRebind<>::type mBase;
    typename tMask::template MRebind<>::type mMask;
};

template<typename tBase,typename tMask>
struct MIsView<CMaskedView<tBase,tMask>>
{
    static const bool value=true;
};

template<typename tBase,typename tMask>
CMaskedView<tBase,tMask> masked_view(const tBase &pBase,const tMask &pMask)
{
    return {pBase,pMask};
}

/*namespace image*/ } /*namespace buola*/ }

#endif
